/*
 * This is where the File IO and Runtime executions are dealt with.
 * All the system calls and the file io is done here.
 */
package com.meraklisina.latex ;

import java.awt.Desktop;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;

/**
 *
 * @author lacertadv7
 */
public class FileIOHandler
{
    private boolean previouslySaved = false ;

    private String filePath = null ;

    private PrintWriter out ;

    File texFile ;

    private String dviName = null ;

    private String pdfName = null ;

    private String fileName = null ;

    private String psName = null ;

    private FileFilter texFilter = new FileNameExtensionFilter( "Tex File", "tex" ) ;

    private FileIOListener[ ] listeners = new FileIOListener[ 5 ] ;

    private String miktexPath ;

    public boolean isPreviouslySaved( )
    {
        return this.previouslySaved ;
    }

    public void setPreviouslySaved( boolean previouslySaved )
    {
        this.previouslySaved = previouslySaved ;
    }

    public String getFilePath( )
    {
        return this.filePath ;
    }

    public String getPdfName( )
    {
        return this.pdfName ;
    }

    public String getFileName( )
    {
        return this.fileName ;
    }

    public void saveTex( String text )
    {
        if( text != null )
        {
            if( !this.isPreviouslySaved( ) || ( this.filePath == null ) )
            {
                JFileChooser fileChooser = new JFileChooser( ) ;
                fileChooser.setFileFilter( this.texFilter ) ;
                int returnVal = fileChooser.showSaveDialog( fileChooser ) ;
                if( returnVal == JFileChooser.APPROVE_OPTION )
                {
                    this.texFile = fileChooser.getSelectedFile( ) ;
                    this.filePath = this.texFile.getAbsolutePath( ) ;
                    this.fileName = this.texFile.getName( ) ;
                    this.filePath = this.filePath.replace( this.fileName, "" ) ;
                    if( !this.fileName.contains( ".tex" ) )
                    {
                        this.fileName = this.fileName.concat( ".tex" ) ;
                    }
                    try
                    {
                        this.out = new PrintWriter( new BufferedWriter( new FileWriter( this.filePath + this.fileName ) ) ) ;
                        this.out.print( text ) ;
                        this.out.close( ) ;
                        this.setPreviouslySaved( true ) ;
                        this.eventOccured( "save", "File saved to " + this.filePath + this.fileName ) ;
                    }
                    catch( IOException ex )
                    {
                        this.eventOccured( "save", "Unable to Save: " + ex.toString( ) ) ;
                        //Logger.getLogger(FileIOHandler.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                else
                {
                    this.eventOccured( "save", "Save Canceled by user." ) ;
                }
            }
            else if( this.filePath != null )
            {
                try
                {
                    this.out = new PrintWriter( new BufferedWriter( new FileWriter( this.filePath + this.fileName ) ) ) ;
                    this.out.print( text ) ;
                    this.out.close( ) ;
                    this.eventOccured( "save", "File saved to " + this.filePath + this.fileName ) ;
                }
                catch( IOException ex )
                {
                    this.eventOccured( "save", "Unable to save: " + ex.toString( ) ) ;
                    //Logger.getLogger(FileIOHandler.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    public void saveAsTex( String text )
    {
        this.setPreviouslySaved( false ) ;
        this.saveTex( null, null, text ) ;
    }

    public void saveTex( String filePath, String fileName, String text )
    {
        if( text != null )
        {
            if( ( ( filePath == "" ) && ( fileName == "" ) ) || !this.isPreviouslySaved( ) )
            {
                JFileChooser fileChooser = new JFileChooser( ) ;
                fileChooser.setFileFilter( this.texFilter ) ;
                int returnVal = fileChooser.showSaveDialog( fileChooser ) ;
                if( returnVal == JFileChooser.APPROVE_OPTION )
                {
                    this.texFile = fileChooser.getSelectedFile( ) ;
                    filePath = this.texFile.getAbsolutePath( ) ;
                    fileName = this.texFile.getName( ) ;
                    filePath = filePath.replace( fileName, "" ) ;
                    this.filePath = filePath ;
                    if( !fileName.contains( ".tex" ) )
                    {
                        fileName = fileName.concat( ".tex" ) ;
                    }
                    this.fileName = fileName ;
                    try
                    {
                        this.out = new PrintWriter( new BufferedWriter( new FileWriter( filePath + fileName ) ) ) ;
                        this.out.print( text ) ;
                        this.out.close( ) ;
                        this.setPreviouslySaved( true ) ;
                        this.eventOccured( "save", "File saved to " + filePath + fileName ) ;
                    }
                    catch( IOException ex )
                    {
                        this.eventOccured( "save", "Unable to Save: " + ex.toString( ) ) ;
                        //Logger.getLogger(FileIOHandler.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                else
                {
                    this.eventOccured( "save", "Save Canceled by user." ) ;
                }
            }
            else if( fileName != "" )
            {
                try
                {
                    this.out = new PrintWriter( new BufferedWriter( new FileWriter( filePath + fileName ) ) ) ;
                    this.out.print( text ) ;
                    this.out.close( ) ;
                    this.fileName = fileName ;
                    this.filePath = filePath ;
                    this.eventOccured( "save", "File saved to " + filePath + fileName ) ;
                }
                catch( IOException ex )
                {
                    this.eventOccured( "save", "Unable to save: " + ex.toString( ) ) ;
                    //Logger.getLogger(FileIOHandler.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    public String getTextForAGivenPath( String fullPath ) throws FileNotFoundException, IOException
    {
        BufferedReader input = new BufferedReader( new FileReader( fullPath ) ) ;
        StringBuilder text = new StringBuilder( ) ;
        String line = null ;
        while( ( line = input.readLine( ) ) != null )
        {
            text.append( line ) ;
            text.append( System.getProperty( "line.separator" ) ) ;
        }
        input.close( ) ;
        return text.toString( ) ;
    }

    public String openTex( )
    {
        JFileChooser fileChooser = new JFileChooser( ) ;
        fileChooser.setFileFilter( this.texFilter ) ;
        int returnVal = fileChooser.showOpenDialog( fileChooser ) ;
        if( returnVal == JFileChooser.APPROVE_OPTION )
        {
            this.texFile = fileChooser.getSelectedFile( ) ;
            this.filePath = this.texFile.getAbsolutePath( ) ;
            this.fileName = this.texFile.getName( ) ;
            this.filePath = this.filePath.replace( this.fileName, "" ) ;
            System.out.println( "File " + this.fileName + " at location " + this.filePath + " loaded." ) ;
            StringBuilder text = new StringBuilder( ) ;
            try
            {
                BufferedReader input = new BufferedReader( new FileReader( this.texFile ) ) ;
                String line = null ;
                while( ( line = input.readLine( ) ) != null )
                {
                    text.append( line ) ;
                    text.append( System.getProperty( "line.separator" ) ) ;
                }
                input.close( ) ;
                this.setPreviouslySaved( true ) ;
                this.eventOccured( "open", "File " + this.filePath + this.fileName + " opened successfully." ) ;

            }
            catch( IOException ex )
            {
                this.eventOccured( "open", "Unable to open tex file: " + ex.toString( ) ) ;
                //Logger.getLogger(FileIOHandler.class.getName()).log(Level.SEVERE, null, ex);
            }
            return text.toString( ) ;
        }
        this.eventOccured( "open", "Open tex file canceled by user" ) ;
        return null ;
    }

    public void tex2DviConverter( )
    {
        if( this.filePath != null )
        {
            try
            {
                Desktop dt = Desktop.getDesktop( ) ;
                Runtime rt = Runtime.getRuntime( ) ;
                String execString = "latex --output-directory=" + this.filePath + " " + this.fileName ;

                if( this.miktexPath != null )
                {
                    execString = "\"" + this.miktexPath + "\\latex.exe\" --output-directory=" + this.filePath + " " + this.fileName ;
                }
                else
                {
                    this.eventOccured( "tex2dvi", "Miktex directory not chosen.\nTrying to find executables from Shell." ) ;
                }
                this.eventOccured( "tex2dvi", "Command executed: " + execString ) ;
                Process pr = rt.exec( execString ) ;
                this.dviName = this.fileName.substring( 0, this.fileName.length( ) - 3 ) ;
                this.dviName = this.dviName.concat( "dvi" ) ;
                File dviFile = new File( this.filePath + this.dviName ) ;
                BufferedReader input = new BufferedReader( new InputStreamReader( pr.getInputStream( ) ) ) ;
                OutputStreamWriter writer = new OutputStreamWriter( new BufferedOutputStream( pr.getOutputStream( ) ) ) ;
                System.out.println( writer ) ;
                String line = null ;

                while( ( line = input.readLine( ) ) != null )
                {
                    System.out.println( "ersin" + line ) ;
                    this.eventOccured( "tex2dvi", "\t" + line ) ;
                }
                int exitVal = pr.waitFor( ) ;
                //synchronized(pr){exitVal = pr.waitFor();};
                System.out.println( "Exited with error code " + exitVal ) ;
                if( exitVal == 0 )
                {
                    this.eventOccured( "tex2dvi", "DVI file created. Opening DVI externally." ) ;
                    dt.open( dviFile ) ;
                    this.eventOccured( "tex2dvi", "DVI file opened externally." ) ;
                }
                else
                {
                    this.eventOccured( "tex2dvi", "Unable to create DVI file." ) ;
                }
            }
            catch( Exception e )
            {
                this.eventOccured( "tex2dvi", "Unable to convert to dvi: " + e.toString( ) ) ;
            }
        }
    }

    public void tex2pdfConverter( )
    {
        if( this.filePath != null )
        {
            try
            {
                //Desktop dt = Desktop.getDesktop();
                Runtime rt = Runtime.getRuntime( ) ;
                String execString = "pdflatex --output-directory=" + this.filePath + " " + this.fileName ;
                if( this.miktexPath != null )
                {
                    execString = "\"" + this.miktexPath + "\\pdflatex.exe\" --output-directory=" + this.filePath + " " + this.fileName ;
                }
                else
                {
                    this.eventOccured( "tex2pdf", "Miktex directory not chosen.\nTrying to find executables from Shell." ) ;
                }
                this.eventOccured( "tex2pdf", "Command executed: " + execString ) ;
                Process pr = rt.exec( execString ) ;
                BufferedReader input = new BufferedReader( new InputStreamReader( pr.getInputStream( ) ) ) ;

                String line = null ;

                while( ( line = input.readLine( ) ) != null )
                {
                    System.out.println( line ) ;
                    this.eventOccured( "tex2pdf", "\t" + line ) ;
                }

                int exitVal = pr.waitFor( ) ;
                System.out.println( "Exited with error code " + exitVal ) ;
                if( exitVal == 0 )
                {
                    //pdfName = fileName.substring(0, fileName.length() - 3);
                    //pdfName = pdfName.concat("pdf");
                    //File pdfFile = new File(filePath + pdfName);
                    this.eventOccured( "tex2pdf", "PDF file created." ) ;
                    //dt.open(pdfFile);
                    //eventOccured("tex2pdf", "PDF file opened externally.");
                }
                else
                {
                    this.eventOccured( "tex2pdf", "Unable to create pdf file." ) ;
                }

            }
            catch( Exception e )
            {
                this.eventOccured( "tex2pdf", "Unable to convert to pdf: " + e.toString( ) ) ;
            }
        }
    }

    public void dvi2psConverter( )
    {
        if( this.filePath != null )
        {
            try
            {
                Desktop dt = Desktop.getDesktop( ) ;
                Runtime rt = Runtime.getRuntime( ) ;
                this.psName = this.fileName.substring( 0, this.fileName.length( ) - 3 ) ;
                this.psName = this.psName.concat( "ps" ) ;
                String execString = "dvips " + this.dviName ;
                if( this.miktexPath != null )
                {
                    execString = "\"" + this.miktexPath + "\\dvips.exe\" -o " + this.filePath + this.psName + " " + this.dviName ;
                }
                else
                {
                    this.eventOccured( "dvi2ps", "Miktex directory not chosen.\nTrying to find executables from Shell." ) ;
                }
                this.eventOccured( "dvi2ps", "Command executed: " + execString ) ;
                System.out.println( execString ) ;
                Process pr = rt.exec( execString ) ;
                BufferedReader input = new BufferedReader( new InputStreamReader( pr.getInputStream( ) ) ) ;
                String line = null ;
                while( ( line = input.readLine( ) ) != null )
                {
                    System.out.println( line ) ;
                    this.eventOccured( "dvi2ps", "\t" + line ) ;
                }
                int exitVal = pr.waitFor( ) ;
                System.out.println( "Exited with error code " + exitVal ) ;
                if( exitVal == 0 )
                {
                    File psFile = new File( this.filePath + this.psName ) ;
                    this.eventOccured( "dvi2ps", "PS file created. Opening PS externally." ) ;
                    dt.open( psFile ) ;
                    this.eventOccured( "dvi2ps", "PS file opened externally." ) ;
                }
                else
                {
                    this.eventOccured( "dvi2ps", "Unable to create ps file." ) ;
                }
            }
            catch( Exception e )
            {
                this.eventOccured( "dvi2ps", "Unable to convert to ps: " + e.toString( ) ) ;
            }
        }
    }

    public synchronized int compileForPreview( String fp, String fn, String text )
    {
        Boolean storePreviouslySaved = this.previouslySaved ;
        this.setPreviouslySaved( true ) ;
        // System.out.println(fp+fileName+" "+this.fileName);
        this.saveTex( fp, fn, text ) ;
        this.filePath = fp ;
        this.fileName = fn ;
        this.tex2pdfConverter( ) ;
        this.setPreviouslySaved( storePreviouslySaved ) ;
        //this.fileName=fileName;
        return 0 ;
    }

    public synchronized void deleteTempPdf( )
    {

        String fileName = "temp" ;
        // A File object to represent the filename
        File f = new File( fileName ) ;

        // Make sure the file or directory exists and isn't write protected
        if( !f.exists( ) )
        {
            System.out.println( "file doesn't exist!" ) ;
        }

        if( !f.canWrite( ) )
        {
            System.out.println( "can't write to file!" ) ;
        }

        // If it is a directory, make sure it is empty
        if( f.isDirectory( ) )
        {
            System.out.println( "Temp folder deleted." ) ;
        }

        // Attempt to delete it
        //    boolean success = f.delete();
        //
        //    if (!success)
        //      System.out.println( "deletion failed");
        f.deleteOnExit( ) ;
    }

    /*
     * Open DVI and PDF files externally
     *
     * */
    public void extDVI( )
    {
        Desktop dt = Desktop.getDesktop( ) ;
        try
        {
            File dviFile = new File( this.filePath + this.dviName ) ;
            dt.open( dviFile ) ;
        }
        catch( Exception ex )
        {
            //Logger.getLogger(FileIOHandler.class.getName()).log(Level.SEVERE, null, ex);
            this.eventOccured( "extDVI", "Unable to open DVI: " + ex.toString( ) + "\nMake sure you compiled it first." ) ;
        }
    }

    public void extPDF( )
    {
        Desktop dt = Desktop.getDesktop( ) ;
        this.pdfName = this.fileName.replace( "tex", "pdf" ) ;
        try
        {
            File pdfFile = new File( this.filePath + this.pdfName ) ;
            dt.open( pdfFile ) ;
        }
        catch( Exception ex )
        {
            //Logger.getLogger(FileIOHandler.class.getName()).log(Level.SEVERE, null, ex);
            this.eventOccured( "extPDF", "Unable to open PDF: " + ex.toString( ) + "\nMake sure you compiled it first." ) ;
        }
    }

    private void eventOccured( String name, String value )
    {
        for( int i = 0; i < this.listeners.length; i++ )
        {
            if( this.listeners[ i ] != null )
            {
                this.listeners[ i ].iOeventOccured( name, value ) ;
            }
        }
    }

    public boolean subscribe( FileIOListener listener )
    {
        for( int i = 0; i < this.listeners.length; i++ )
        {
            if( this.listeners[ i ] == null )
            {
                this.listeners[ i ] = listener ;
                return true ;
            }
        }
        return false ;
    }

    public void loadConfigFile( )
    {
        JFileChooser fileChooser = new JFileChooser( ) ;
        fileChooser.setFileFilter( new FileNameExtensionFilter( "Text File", "txt" ) ) ;
        int returnVal = fileChooser.showDialog( fileChooser, "Open config.txt" ) ;
        if( returnVal == JFileChooser.APPROVE_OPTION )
        {
            File configFile = fileChooser.getSelectedFile( ) ;
            //   filePath = texFile.getAbsolutePath();
            //File configFile = new File("config.txt");
            BufferedReader input ;
            try
            {
                input = new BufferedReader( new FileReader( configFile ) ) ;
                String line = null ;
                line = input.readLine( ) ;
                input.close( ) ;
                this.miktexPath = line ;
                this.eventOccured( "loadConfigFile", this.miktexPath ) ;
            }
            catch( Exception ex )
            {
                Logger.getLogger( FileIOHandler.class.getName( ) ).log( Level.SEVERE, null, ex ) ;
            }
        }
        else
        {
            this.eventOccured( "loadConfigFile", "Cofig file not chosen.\nMiktex directory not chosen.\nWill try to find executables from Shell." ) ;
        }
    }

    public FileIOHandler( )
    {
    }
}
